package com.canaan.business.service.bill.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.InStockOrderTypeEnum;
import com.canaan.business.common.enums.inOutStock.OutOrderStatusEnum;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.bill.ScrapProductBill;
import com.canaan.business.domain.bill.ScrapProductBillDetail;
import com.canaan.business.domain.inOutStock.WmsInStockDetailOrder;
import com.canaan.business.domain.inOutStock.WmsInStockOrder;
import com.canaan.business.domain.vo.ScrapProductBillExportVo;
import com.canaan.business.domain.vo.ScrapProductBillVo;
import com.canaan.business.mapper.bill.ScrapProductBillMapper;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.bill.IScrapProductBillDetailService;
import com.canaan.business.service.bill.IScrapProductBillService;
import com.canaan.business.service.inOutStock.IWmsInStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsInStockOrderService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 报废单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-01-31
 */
@Service
public class ScrapProductBillServiceImpl implements IScrapProductBillService {
    @Resource
    private ScrapProductBillMapper scrapProductBillMapper;
    @Resource
    private IScrapProductBillDetailService scrapProductBillDetailService;
    @Resource
    private IWmsInStockOrderService wmsInStockOrderService;
    @Resource
    private IWmsInStockDetailOrderService wmsInStockDetailOrderService;
    @Resource
    private IWmsProductService wmsProductService;

    /**
     * 查询报废单
     *
     * @param id 报废单主键
     * @return 报废单
     */
    @Override
    public ScrapProductBill selectScrapProductBillById(Long id) {
        return scrapProductBillMapper.selectScrapProductBillById(id);
    }

    /**
     * 查询报废单列表
     *
     * @param scrapProductBill 报废单
     * @return 报废单
     */
    @Override
    public List<ScrapProductBill> selectScrapProductBillList(ScrapProductBill scrapProductBill) {
        return scrapProductBillMapper.selectScrapProductBillList(scrapProductBill);
    }

    /**
     * 新增报废单
     *
     * @param scrapProductBill 报废单
     * @return 结果
     */
    @Override
    public int insertScrapProductBill(ScrapProductBill scrapProductBill) {
        if(scrapProductBill==null){
            throw new ServiceException("数据对象为空");
        }
        if (StringUtils.isEmpty(scrapProductBill.getStorehouseNo())){
            throw new ServiceException("线边仓不能为空");
        }
        if(StringUtils.isBlank(scrapProductBill.getNo())){
            scrapProductBill.setNo(PrefixConstants.SCRAP+TableNoUtil.getNo(ScrapProductBill.class));
        }
        scrapProductBill.setStorehouseNo(scrapProductBill.getStorehouseNo());
        scrapProductBill.setStorehouseName(scrapProductBill.getStorehouseName());
        scrapProductBill.setCreateTime(DateUtils.getNowDate());
        scrapProductBill.setCreateBy(SecurityUtils.getUsername());
        scrapProductBill.setCreateTime(DateUtils.getNowDate());
        scrapProductBill.setStatus(OutOrderStatusEnum.NEW.getCode());
        List<ScrapProductBillDetail> productBillDetailList = scrapProductBill.getScrapProductBillDetailList();
        if (CollUtil.isNotEmpty(productBillDetailList)){
            productBillDetailList.stream().forEach(e->{
                e.setNo(TableNoUtil.getNo(ScrapProductBillDetail.class));
                e.setBillNo(scrapProductBill.getNo());
                e.setCreateBy(SecurityUtils.getUsername());
                e.setCreateTime(DateUtils.getNowDate());
            });
            //汇总数量
            scrapProductBill.setTotalQty(scrapProductBill.getScrapProductBillDetailList().stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
            //生成物料清单
            scrapProductBill.getScrapProductBillDetailList().stream().forEach(e->{
                WmsProduct product = this.wmsProductService.selectWmsProductByProductNo(e.getProductNo());
                if (product!=null){
                    e.setProductUnit(product.getCompany());
                }
            });
            this.scrapProductBillDetailService.batchInsertScrapProductBillDetail(scrapProductBill.getScrapProductBillDetailList());
        }
        //生成报废申请单
        int i= scrapProductBillMapper.insertScrapProductBill(scrapProductBill);
        //生成报废入库单
        WmsInStockOrder wmsInStockOrder = new WmsInStockOrder();
        wmsInStockOrder.setNo(TableNoUtil.getNo(WmsInStockOrder.class));
        wmsInStockOrder.setOrderType(InStockOrderTypeEnum.SCRAP.getCode());
        wmsInStockOrder.setRelOrderNo(scrapProductBill.getNo());
        wmsInStockOrder.setArea(scrapProductBill.getArea());
        wmsInStockOrder.setOrderStatus(InOrderStatusEnum.NEW.getCode());
        wmsInStockOrderService.insertWmsInStockOrder(wmsInStockOrder);
        List<WmsInStockDetailOrder> stockDetailOrders = new ArrayList<>();
        for (ScrapProductBillDetail scrapProductBillDetail : productBillDetailList) {
            WmsInStockDetailOrder detailOrder = new WmsInStockDetailOrder();
            detailOrder.setOrderNo(wmsInStockOrder.getNo());
            detailOrder.setProductNo(scrapProductBillDetail.getProductNo());
            detailOrder.setOrderDetailStatus(InOrderStatusEnum.NEW.getCode());
            detailOrder.setOrderQty(scrapProductBillDetail.getQty());
            stockDetailOrders.add(detailOrder);
        }
        if (CollUtil.isNotEmpty(stockDetailOrders)) {
            wmsInStockDetailOrderService.batchInsertInStockDetailOrder(stockDetailOrders);
        }
        return i;
    }

    /**
     * 批量新增报废单
     *
     * @param scrapProductBillList 报废单列表
     * @return 结果
     */
    @Override
    public int batchInsertScrapProductBill(List<ScrapProductBill> scrapProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (ScrapProductBill scrapProductBill : scrapProductBillList){
            if(StringUtils.isBlank(scrapProductBill.getNo())){
                scrapProductBill.setNo(TableNoUtil.getNo(ScrapProductBill.class));
            }
            scrapProductBill.setCreateBy(username);
            scrapProductBill.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<scrapProductBillList.size();) {
            int endIndex = i+500;
            if (endIndex > scrapProductBillList.size()) {
                endIndex = scrapProductBillList.size();
            }
            insertNum = insertNum + scrapProductBillMapper.batchInsertScrapProductBill(scrapProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改报废单
     *
     * @param scrapProductBill 报废单
     * @return 结果
     */
    @Override
    public int updateScrapProductBill(ScrapProductBill scrapProductBill) {
        scrapProductBill.setUpdateBy(SecurityUtils.getUsername());
        scrapProductBill.setUpdateTime(DateUtils.getNowDate());
        return scrapProductBillMapper.updateScrapProductBill(scrapProductBill);
    }

    /**
     * 批量修改报废单
     *
     * @param scrapProductBillList 报废单列表
     * @return 结果
     */
    @Override
    public int batchUpdateScrapProductBill(List<ScrapProductBill> scrapProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (ScrapProductBill scrapProductBill : scrapProductBillList){
            scrapProductBill.setUpdateBy(username);
            scrapProductBill.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<scrapProductBillList.size();) {
            int endIndex = i+500;
            if (endIndex > scrapProductBillList.size()) {
                endIndex = scrapProductBillList.size();
            }
            updateNum = updateNum + scrapProductBillMapper.batchUpdateScrapProductBill(scrapProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除报废单
     *
     * @param ids 需要删除的报废单主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteScrapProductBillByIds(Long[] ids) {
        ScrapProductBill bill = new ScrapProductBill();
        bill.setIds(CollUtil.toList(ids));
        List<ScrapProductBill> billList = this.selectScrapProductBillList(bill);
        List<String> nos = billList.stream()
                .filter(e -> OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(e.getStatus())
                        || OutOrderStatusEnum.ACCOMPLISH.getCode().equals(e.getStatus()))
                .map(ScrapProductBill::getNo).collect(Collectors.toList());
        if(!nos.isEmpty()){
            throw new ServiceException("取消待确认或已完成状态的单据不能删除");
        }
        for (ScrapProductBill productBill : billList) {
            if(InOrderStatusEnum.PICKING.getCode().equals(productBill.getStatus())){
                //校验进行中单据下的出入库单数据
                WmsInStockOrder stockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(productBill.getNo(), InStockOrderTypeEnum.SCRAP.getCode());
                if(stockOrder != null && stockOrder.getTotalActualQty() > 0){
                    nos.add(productBill.getNo());
                }
            }
        }
        if(!nos.isEmpty()){
            throw new ServiceException(nos + "单据已有实际入库数量不能删除");
        }
        //入库单和入库单明细删除
        nos = billList.stream().map(ScrapProductBill::getNo).collect(Collectors.toList());
        wmsInStockOrderService.deleteWmsInStockOrderByRelOrderNosAndType(nos, InStockOrderTypeEnum.SCRAP.getCode());

        return scrapProductBillMapper.deleteScrapProductBillByIds(ids);
    }

    /**
     * 删除报废单信息
     *
     * @param id 报废单主键
     * @return 结果
     */
    @Override
    public int deleteScrapProductBillById(Long id) {
        return scrapProductBillMapper.deleteScrapProductBillById(id);
    }

    /**
     * 查询报废单
     *
     * @param no 编号
     * @return 报废单
     */
    @Override
    public ScrapProductBill selectScrapProductBillByNo(String no) {
        return scrapProductBillMapper.selectScrapProductBillByNo(no);
    }

    /**
     * 批量删除报废单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteScrapProductBillByNos(String[] nos) {
        return scrapProductBillMapper.deleteScrapProductBillByNos(nos);
    }

    /**
     * 删除报废单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteScrapProductBillByNo(String no) {
        return scrapProductBillMapper.deleteScrapProductBillByNo(no);
    }

    @Override
    public int addWithDetail(ScrapProductBillVo scrapProductBillVo) {
        List<ScrapProductBillDetail> scrapProductBillDetailList = scrapProductBillVo.getScrapProductBillDetailList();
        ScrapProductBill scrapProductBill = BeanUtil.toBean(scrapProductBillVo, ScrapProductBill.class);
        scrapProductBill.setTotalQty(scrapProductBillDetailList.stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
        this.insertScrapProductBill(scrapProductBill);
        if (CollUtil.isNotEmpty(scrapProductBillDetailList)) {
            scrapProductBillDetailList.forEach(e -> e.setBillNo(scrapProductBill.getNo()));
            scrapProductBillDetailService.batchInsertScrapProductBillDetail(scrapProductBillDetailList);
        }
        return 1;
    }

    @Override
    public List<ScrapProductBillExportVo> exportList(ScrapProductBill scrapProductBill) {
        return scrapProductBillMapper.exportList(scrapProductBill);
    }

    @Override
    @Transactional
    public int cancel(List<Long> ids) {
        ScrapProductBill bill = new ScrapProductBill();
        bill.setIds(ids);
        List<ScrapProductBill> billList = this.selectScrapProductBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.NEW.getCode().equals(e.getStatus())
                || OutOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        for (ScrapProductBill scrapProductBill : billList) {
            WmsInStockOrder wmsInStockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(scrapProductBill.getNo(), InStockOrderTypeEnum.STORES_RETURNED.getCode());
            if (wmsInStockOrder!=null) {
                if (wmsInStockOrder.getTotalActualQty() > 0){
                    throw new ServiceException("已入库不允许取消，单号：" + scrapProductBill.getNo());
                }
                wmsInStockOrder.setOrderStatus(InOrderStatusEnum.CANCEL.getCode());
                this.wmsInStockOrderService.updateWmsInStockOrder(wmsInStockOrder);
            }
        }
        billList.stream().forEach(e -> e.setStatus(InOrderStatusEnum.CANCEL.getCode()));
        this.batchUpdateScrapProductBill(billList);
        return billList.size();
    }

    /**
     * 确认取消
     * @param bill 单据信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmCancel(ScrapProductBill bill) {
        bill = this.selectScrapProductBillById(bill.getId());
        if(bill == null){
            throw new ServiceException("单据不存在");
        }else if(!InOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(bill.getStatus())){
            throw new ServiceException("该状态不是取消待确认，无法确认取消");
        }

        WmsInStockOrder stockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(bill.getNo(), InStockOrderTypeEnum.STORES_RETURNED.getCode());
        if(stockOrder != null){
            stockOrder.setOrderStatus(InOrderStatusEnum.CANCEL.getCode());
            wmsInStockOrderService.updateWmsInStockOrder(stockOrder);
        }
        bill.setStatus(InOrderStatusEnum.CANCEL.getCode());
        return this.updateScrapProductBill(bill);
    }
}
